/*
 * Licensed Materials - Property of tenxcloud.com
 * (C) Copyright 2018 TenxCloud. All Rights Reserved.
 * 2018-11-06  @author lizhen
 */

package permission

import (
	"github.com/jinzhu/gorm"
	"modules.tenxcloud.com/common/contract"
	"regexp"
)

func PermissionsOfUserInProject(userID int, project string, db *gorm.DB) (codes []string, err error) {
	var result []*struct {
		Code string `gorm:"column:code"`
	}
	if err = db.Raw(`SELECT DISTINCT tenx_permission.code AS code
FROM tenx_user_role
       LEFT JOIN tenx_project ON tenx_user_role.scope_id = tenx_project.id
       LEFT JOIN tenx_permission_role ON tenx_user_role.role_id = tenx_permission_role.role_id
       LEFT JOIN tenx_permission ON tenx_permission_role.permission_id = tenx_permission.id
WHERE tenx_user_role.user_id = ?
  AND ((tenx_user_role.scope = 0 AND tenx_user_role.scope_id = 'global') OR tenx_project.name = ?);`,
		userID, project).Scan(&result).Error; err != nil {
		return
	}
	if result == nil {
		return
	}
	count := len(result)
	codes = make([]string, count)
	for i := 0; i < count; i++ {
		codes[i] = result[i].Code
	}
	return
}

type acl struct {
	FT string `gorm:"column:filter_type"`
	PT string `gorm:"column:policy_type"`
	FC string `gorm:"column:filter"`
}

func (a acl) FilterType() contract.FilterType {
	return contract.FilterType(a.FT)
}

func (a acl) PolicyType() contract.PolicyType {
	return contract.PolicyType(a.PT)
}

func (a acl) Filter(name string) (match bool, err error) {
	if filterType := a.FilterType(); filterType == contract.FixedFilter {
		match = a.FC == name
		return
	} else if filterType == contract.RegexFilter {
		var pattern *regexp.Regexp
		if pattern, err = regexp.Compile(a.FC); err != nil {
			return
		}
		match = pattern.MatchString(name)
	}
	return
}

func ACLsOfUserInProjectInCluster(userID int, projectName, clusterID, code string, db *gorm.DB) (acls []contract.ACL, err error) {
	var models []*acl
	if err = db.Raw(`SELECT tenx_resource_role_ref.*
FROM tenx_resource_role_ref
       LEFT JOIN tenx_project_role ON tenx_resource_role_ref.role_id = tenx_project_role.role_id
       LEFT JOIN tenx_permission ON tenx_resource_role_ref.permission_id = tenx_permission.id
       LEFT JOIN tenx_user_role ON tenx_project_role.role_id = tenx_user_role.role_id
       LEFT JOIN tenx_project_user ON tenx_project_role.project_id = tenx_project_user.project_id
       LEFT JOIN tenx_project ON tenx_project_role.project_id = tenx_project.id
WHERE tenx_user_role.user_id = ?
  AND tenx_user_role.scope = 200
  AND tenx_user_role.scope_id = tenx_project.id
  AND tenx_user_role.user_id = tenx_project_user.user_id
  AND tenx_permission.code = ?
  AND tenx_resource_role_ref.cluster_id = ?
  AND tenx_project.namespace = ?;`, userID, code, clusterID, projectName).Scan(&models).Error; err != nil {
		return
	}
	acls = toContract(models)
	return
}

func toContract(acls []*acl) (contracts []contract.ACL) {
	if acls == nil {
		return
	}
	count := len(acls)
	contracts = make([]contract.ACL, count)
	for i := 0; i < count; i++ {
		contracts[i] = acls[i]
	}
	return
}
